/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8     -*-│
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8                                     :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney                              │
│                                                                              │
│ Permission to use, copy, modify, and/or distribute this software for         │
│ any purpose with or without fee is hereby granted, provided that the         │
│ above copyright notice and this permission notice appear in all copies.      │
│                                                                              │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
│ PERFORMANCE OF THIS SOFTWARE.                                                │
╠──────────────────────────────────────────────────────────────────────────────╣
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│
│░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│
│░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│
╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│
│ αcτµαlly pδrταblε εxεcµταblε § program header                                │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "ape/macros.internal.h"
#include "ape/notice.inc"
#include "ape/relocations.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/macho.internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nexgen32e/vidya.internal.h"
#include "libc/nt/pedef.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/sysv/consts/prot.h"

#define USE_SYMBOL_HACK 1

	.section .text,"ax",@progbits
	.align	__SIZEOF_POINTER__
	.previous
	.section .rodata,"a",@progbits
	.align	__SIZEOF_POINTER__
__ro:	.endobj	__ro,globl,hidden		# ←for gdb readibility
	.previous
	.section .data,"aw",@progbits
	.align	__SIZEOF_POINTER__
	.previous
	.section .bss,"aw",@nobits
	.align	__SIZEOF_POINTER__
	.previous
	.section .rodata.str1.1,"a",@progbits
cstr:	.endobj	cstr,globl,hidden		# ←for gdb readibility
	.previous
	.section .head,"ax",@progbits

/*	    ████████               ████████        ███████████
	    ██░░░░▒▒██           ██░░░░▒▒██    ████░░░░░░░░░▒▒████
	    ██░░░░░░██           ██░░░░▒▒██  ██░░░░▒▒███████░░░░▒▒██
	    ██░░░░░░▒▒██      ░██░░░░░░▒▒██  ██░░▒▒██       ██░░▒▒██
	    ██░░▒▒░░░░██      ░██░░░░░░▒▒██  ██░░▒▒██       ████████
	    ██░░▒▒▒▒░░▒▒██  ██▓░░░░▒▒░░▒▒██  ██░░▒▒▒▒███████
	    ██░░▒▒██░░░░██  ██▓░░░░██░░▒▒██    ████░░░░░░░▒▒████
	    ██░░▒▒████░░▒▒██░░░░░████░░▒▒██        ███████░░░░▒▒██
	    ██░░▒▒████░░░░██░░░░░████░░▒▒██  ██████       ██░░░░▒▒██
	    ██░░▒▒██  ██░░▒▒░░▒██  ██░░▒▒██  ██░░░░██       ██░░▒▒██
	    ██░░▒▒██  ██░░░░░░▒██  ██░░▒▒██  ██░░░░█████████░░░░▒▒██
	    ██░░▒▒██  ▓▓▒▒░░▒▒▒▓▓  ██░░▒▒██  ▓▓▒▒░░▓▓▓▓▓▓▓▓▓░░░░▓▓▓▓
	    ██░░▒▒██    ██░░██▓    ██░░▒▒██    ██░░░░░░░░░░░░░▒▒██
	  ████████████████████▓  ██████████████  ███████████████
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░████
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓█████▓▓░░▓▓░░▓▓░░████░░░░░░░░░░░░░░░░░░░░░██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▒░░▓▓░░▓▓░░▓▓██░░░░░░░░░░░░░░░░░░░░░░░░░██
	  ██▓▓▓▓▓▓██████████░░▒▓▓▓▓██████▓▓██░░░░░░███████████▓▓░░░░▓▓██
	  ██▓▓▓▓▓▓████████░░▓▓▓▓▓██▓▓▓▓██████░░░░████░░▒▓▓██  ██▓▓▓▓▓▓██
	  ██▓▓▓▓▓▓████████▓▓░░▒████▓▓▓▓██████░░░░██▓▓▓▓▒░░██    ██████
	  ██▓▓▓▓▓▓██    ██░░▓▓▓▓▓██▓▓▓▓██  ██▓▓░░████░░▒▓▓██████
	  ██▓▓▓▓▓▓██    ██▓▓░░▒████▓▓▓▓██    ██▓▓██▓▓▓▓▒░░██░░░░████
	  ██▓▓▓▓▓▓██    ██░░▓▓▓▓▓██▓▓▓▓██      ██████░░▒▓▓██░░░░░░░░██
	  ██▓▓▓▓▓▓██    ██▓▓░░▒████▓▓▓▓██        ██▓▓▓▓▒░░██▓▓░░░░░░░░██
	  ██▓▓▓▓▓▓██    ██░░▓▓▓████▓▓▓▓██    ████████░░▒▓▓████▓▓░░░░░░██
	  ██▓▓▓▓▓▓██      ██░░▒██▓▓▓▓████  ██░░░░░░██▓▓███    ██░░░░░░██
	  ██▓▓▓▓▓▓█████████████▓▓▓▓██████████▓▓░░░░░░█████████░░░░░░░░██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░██▓▓░░░░░░░░░░░░░░░░░░░░░▓▓██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓██▓▓▓▓░░░░░░░░░░░░░░░░░▓▓▓▓██
	  ██▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████▓▓░░▓▓░░▓▓██▓▓▓▓▓▓░░░░░░░░░░░▓▓▓▓▓▓██
	  ██▓▓█████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██
	  ███████████████████████████▓▓██▓▓██▓▓████▓▓▓▓▓▓▓▓▓▓▓▓▓████
	    ██████████████████▓    ██████████████  █████████████
╔──────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § the old technology                            │
╚─────────────────────────────────────────────────────────────────────────────*/

#if SupportsWindows() || SupportsMetal() || SupportsXnu()

//	MZ Literally Executable Header
//
//	This is the beginning of the program file and it can serve as an
//	entrypoint too. It shouldn't matter if the program is running on
//	Linux, Windows, etc. Please note if the underlying machine isn't
//	a machine, this header may need to morph itself to say the magic
//	words, e.g. ⌂ELF, which also works fine as a generic entrypoint.
//
//	@param	dl is drive number
//	@noreturn
ape_mz:	.asciz	"MZqFpD='\n"		# Mark 'Zibo' Joseph Zbikowski
	.short	0x1000			# MZ: lowers upper bound load / 16
	.short	0xf800			# MZ: roll greed on bss
	.short	0			# MZ: lower bound on stack segment
	.short	0			# MZ: initialize stack pointer
	.short	0			# MZ: ∑bₙ checksum don't bother
	.short	0x0100			# MZ: initial ip value
	.short	0x0800			# MZ: increases cs load lower bound
	.short	0x0040			# MZ: reloc table offset
	.short	0			# MZ: overlay number
	.org	0x24			# MZ: bytes reserved for you
	.ascii	"JT"			# MZ: OEM identifier
	.short	0			# MZ: OEM information
	.org	0x40-4			# MZ: bytes reserved for you
#if SupportsWindows() || SupportsMetal()
	.long	RVA(ape_pe)		# PE: the new technology
#else
	.long	0
#endif
	.endfn	ape_mz,globl,hidden

#else /* !(SupportsWindows() || SupportsMetal() || SupportsXnu()) */

//	ELF Literally Executable Header
//
//	If we don't need to support Microsoft or Apple then we can
//	produce a conventional executable without the shell script
//
//	@param	dl is drive number
//	@noreturn
	.ascii	"\177ELF"			# 0x0: ⌂ELF
	.byte	ELFCLASS64			#   4: long mode
	.byte	ELFDATA2LSB			#   5: little endian
	.byte	1				#   6: elf v1.o
	.byte	ELFOSABI_FREEBSD		#   7: FreeBSD
	.byte	0				#   8: os/abi ver.
	.align	8,0				#   9: padding
	.short	ET_EXEC				#  10: εxεcµταblε
	.short	EM_NEXGEN32E			#  12: NexGen32e
	.long	1				#  14: elf v1.o
	.quad	ape_elf_entry			#  18: e_entry
	.quad	ape_elf_phoff			#  20: e_phoff
	.quad	ape_elf_shoff			#  28: e_shoff
	.long	0				#  30: e_flags
	.short	64				#  34: e_ehsize
	.short	56				#  36: e_phentsize
	.short	ape_elf_phnum			#  38: e_phnum
	.short	0				#  3a: e_shentsize
	.short	ape_elf_shnum			#  3c: e_shnum
	.short	ape_elf_shstrndx		#  3e: e_shstrndx

#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */

#if SupportsMetal()

//	Disk Operating System Stub
//
//	@param	dl is drive number
//	@noreturn
	.org	0x40			# mz/elf header length
stub:	mov	$0x40,%dl		# *literally* dos
	jmp	1f			# good bios skips here
1:	jmp	pc			# thus avoiding heroics
	nop				# system five bootpoint
	.org	0x48,0x90		# note ⌂ELF means JG 47
	jmp	3f			# MZ also means pop r10
2:	sub	$8,%rsp			# a.k.a. dec %ax sub %sp
	xor	%edx,%edx		# MZ ate BIOS drive code
3:	.byte	0xbd,0,0		# a.k.a. mov imm,%bp
	jmp	pc			# real mode, is real
	jmp	_start			# surprise it's unix
	.endfn	stub

/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § ibm personal computer                         │
╚──────────────────────────────────────────────────────────────────────────────┘
	IBM designed BIOS to run programs by handing over the computer
	to a program as soon as its first sector is loaded. That gives
	us control over user-facing latency, even though the next step
	will generally be asking the BIOS to load more.
	
	The process is trivial enough that this entrypoint can support
	handoffs from alternative program-loaders e.g. Grub and MS-DOS
	so long as they either load our full program, or implement the
	PC BIOS disk service API.
	
	Since so many different implementations of these APIs have been
	built the last forty years these routines also canonicalize the
	cpu and program state, as it is written in the System V ABI. */

//	Initializes program and jumps to real mode loader.
//
//	@param	dl drive number (use 0x40 to skip bios disk load)
//	@mode	real
//	@noreturn
pc:	cld
	.code16
#if USE_SYMBOL_HACK
	.byte	0x0f,0x1f,0207			# nop rdi binbase
	.short	(0x7c00-IMAGE_BASE_VIRTUAL)/512
#endif
	mov	$0x70000>>4,%di			# we need a stack
	xor	%cx,%cx				# 0x7f000-0x80000
	mov	%cx,%es
	rlstack	%di,%cx
	push	%cs				# determine load address
	pop	%ds				# and relocate this code
	call	1f				# to a way lower address
1:	pop	%si				# and we'll make cs zero
	sub	$RVA(1b),%si
	mov	$IMAGE_BASE_REAL>>4,%ax
	push	%ax				# save IMAGE_BASE_REAL>>4
	push	%ax
	pop	%es
	xor	%di,%di
	mov	$512,%cx
	rep movsb
#if USE_SYMBOL_HACK
	.byte	0x0f,0x1f,0207			# nop rdi binbase
	.short	(IMAGE_BASE_REAL-0x7c00)/512
#endif
	ljmp	$0,$REAL(1f)
1:	mov	%cx,%ds
	mov	$IMAGE_BASE_REAL-0x0500,%cx	# clears bss
	mov	$0x0500>>4,%ax			# struct mman
	mov	%ax,%es
	xor	%ax,%ax
	xor	%di,%di
	rep stosb
	cmp	$0x40,%dl
	je	6f
	call	dsknfo
	pop	%es				# restore IMAGE_BASE_REAL>>4
	mov	$1,%al				# current sector
	xor	%cx,%cx				# current cylinder
	xor	%dh,%dh				# current head
	mov	$v_ape_realsectors,%di		# total sectors
3:	call	pcread
	dec	%di
	jnz	3b
6:	ljmp	$0,$REAL(realmodeloader)
	.endfn	pc

//	Determines disk geometry.
//
//	We use imperial measurements for storage systems so the software
//	can have an understanding of physical locality, which deeply
//	impacts the latency of operations.
//
//	 - 160KB:  40 cylinders × 1 head  ×  8 sectors × 512 =   163,840
//	 - 180KB:  40 cylinders × 1 head  ×  9 sectors × 512 =   184,320
//	 - 320KB:  40 cylinders × 2 heads ×  8 sectors × 512 =   327,680
//	 - 360KB:  40 cylinders × 2 heads ×  9 sectors × 512 =   368,640
//	 - 720KB:  80 cylinders × 2 heads ×  9 sectors × 512 =   737,280
//	 - 1.2MB:  80 cylinders × 2 heads × 15 sectors × 512 = 1,228,800
//	 - 1.44MB: 80 cylinders × 2 heads × 18 sectors × 512 = 1,474,560
//
//	Terminology
//
//	 - Heads are also known as Tracks
//
//	Disk Base Table
//
//	   0: specify byte 1, step-rate time, head unload time
//	   1: specify byte 2, head load time, DMA mode
//	   2: timer ticks to wait before disk motor shutoff
//	   3: bytes per sector code
//	        0: 128 bytes  2: 512 bytes
//	        1: 256 bytes  3: 1024 bytes
//	   4: sectors per track (last sector number)
//	   5: inter-block gap length/gap between sectors
//	   6: data length, if sector length not specified
//	   7: gap length between sectors for format
//	   8: fill byte for formatted sectors
//	   9: head settle time in milliseconds
//	  10: motor startup time in eighths of a second
//
//	@param	dl drive number
//	@return	dl = pc_drive (corrected if clobbered by header)
//		pc_drive
//		pc_drive_type
//		pc_drive_heads
//		pc_drive_last_cylinder
//		pc_drive_last_sector
//	@clob	ax, cx, dx, di, si, es, flags
//	@since	IBM Personal Computer XT
dsknfo:	push	%bx
1:	push	%dx
	mov	$0x08,%ah		# get disk params
	int	$0x13
	jc	9f
	mov	%cl,%bh
	and	$0b00111111,%bh
	and	$0b11000000,%cl
	rol	%cl
	rol	%cl
	xchg	%cl,%ch
	push	%ds			# disk base table in es:di
	movpp	%es,%ds
	xor	%si,%si
	mov	%si,%es
	mov	$0x1510,%si		# mman::pc_drive_base_table
	xchg	%si,%di
	movsw	#→ headunloadtime, headloadtime
	movsw	#→ shutofftime, bytespersector
	movsw	#→ sectorspertrack, sectorgap
	movsw	#→ datalength, formatgap
	movsw	#→ formatfill, settletime
	movsb	#→ startuptime
	pop	%ds
	xchg	%bx,%ax
	stosw	#→ pc_drive_type, pc_drive_last_sector
	xchg	%cx,%ax
	stosw	#→ pc_drive_last_cylinder
	xchg	%dx,%ax
	stosw	#→ pc_drives_attached, pc_drive_last_head
	pop	%ax
	stosb	#→ pc_drive
	xchg	%ax,%dx
	pop	%bx
	ret
9:	pop	%dx
8:	xor	$0x80,%dl		# try cycling drive a/c
	xor	%ax,%ax			# reset disk
	int	$0x13
	jc	8b
	jmp	1b
	.endfn	dsknfo

//	Reads disk sector via BIOS.
//
//	@param	al sector number
//	@param	es destination memory address >> 4
//	@param	cx cylinder number
//	@param	dh head number
//	@param	dl drive number
//	@return	number of sectors actually read
pcread:	push	%ax
	push	%cx
	xchg	%cl,%ch
	ror	%cl
	ror	%cl
	or	%al,%cl
	xor	%bx,%bx			# es:bx is destination addr
	mov	$1,%al			# read only one disk sector
	mov	$2,%ah			# read disk sectors ordinal
	int	$0x13
	pop	%cx
	pop	%ax
	jc	9f
	mov	%es,%si			# addr += 512
	add	$512>>4,%si
	mov	%si,%es
	inc	%al			# ++sector
	cmp	0x151c,%al		# mman::pc_drive_last_sector
	jbe	2f
	mov	$1,%al
	inc	%dh			# ++head
	cmp	0x1520,%dh		# mman::pc_drive_last_head
	jbe	2f
	xor	%dh,%dh
	inc	%cx			# ++cylinder
2:	ret
9:	push	%ax
	xor	%ax,%ax			# try disk reset on error
	int	$0x13
	pop	%ax
	jmp	pcread
	.endfn	pcread

//	Video put string.
//
//	@param	di is the string
//	@clob	bp,bx
//	@mode	real
rvputs:	mov	%di,%si
0:	lodsb
	test	%al,%al
	je	1f
	mov	$7,%bx				# normal mda/cga style page zero
	mov	$0x0e,%ah			# teletype output al cp437
	int	$0x10				# vidya service
	jmp	0b
1:	ret
	.endfn	rvputs

//	Abnormally halts startup.
//
//	@param	di message
//	@mode	real
//	@noreturn
rldie:	push	%di
	mov	$REAL(str.error),%di
	call	rvputs
	pop	%di
	call	rvputs
	mov	$REAL(str.crlf),%di
	call	rvputs
0:	rep nop
	jmp	0b
	.endfn	rldie

//	Initializes present PC serial lines.
sinit4:	mov	$4,%cx
	mov	$0x400,%si			# BDA.COM1
0:	lodsw
	test	%ax,%ax
	jz	1f
	push	%cx
	push	%si
	xchg	%ax,%di
	mov	$REAL(sconf),%si
	call	sinit
	pop	%si
	pop	%cx
1:	loop	0b
	ret
	.endfn	sinit4,global,hidden

//	Initializes Serial Line Communications 8250 UART 16550A
//
//	@param	word di tty port
//	@param	char (*{es:,e,r}si)[4] register initial values
//	@mode	long,legacy,real
//	@see	www.lammertbies.nl/comm/info/serial-uart.html
sinit:	mov	%di,%dx
	test	%dx,%dx
	jz	2f
	push	%dx
	push	%si
	xor	%cx,%cx
	mov	$UART_LCR,%cl
	add	%cx,%dx
	lodsb	%ds:(%si),%al
	pop	%si
	or	$UART_DLAB,%al
	out	%al,%dx
	pop	%dx
1:	lodsb	%ds:(%si),%al
	out	%al,%dx
	inc	%dx
	dec	%cx
	jns	1b
2:	ret
	.endfn	sinit,global,hidden

/*───────────────────────────────────────────────────────────────────────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § partition table                           ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│*/

//	Partition Table.
ape.mbrpad:
	.org	0x1b4
	.endobj	ape.mbrpad
ape_disk:
	.stub	ape.diskid,quad
	.org	0x1be,0x00
	.macro	.partn	x
	.stub	ape.part\x\().status,byte	# 0=absent / 0x80=present
	.stub	ape.part\x\().first.head,byte	# in low 6 bits
	.stub	ape.part\x\().first.cylinder,byte
	.stub	ape.part\x\().first.sector,byte
	.stub	ape.part\x\().filesystem,byte
	.stub	ape.part\x\().last.head,byte
	.stub	ape.part\x\().last.cylinder,byte
	.stub	ape.part\x\().last.sector,byte
	.stub	ape.part\x\().lba,long          # c₀*Cₙ + h₀*Hₙ + s₀*Sₙ
	.stub	ape.part\x\().sector.count,long # sectors are 512 bytes
	.endm
	.partn	1
	.partn	2
	.partn	3
	.partn	4
	.org	0x1fe
	.short	BOOTSIG
	.endobj	ape_disk

#endif /* SupportsMetal() */

/*                                           ▄▄▄
                       ▄▄▄                    ▀▓▓▒▄
                     ▄▓▒▒░                      ▀▓▒▒▒▄
                   ▄▓▓▓▒▀              ▄▄▄▄      ▒▓▒▒░▒▄
                  ▄▓▓▓▒▓        ▄▄▓██▓▓▓▓▒▒▒▒▓▓▄▄▓▓▒▒▒░░▒
                  ▓▓▓▓▒▒▒▄▄  ░▒█▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓▒░░▒░
                  ██▓▓▓▒▒░░▒▒▒▒▓▓▓▓▓▓▒▓▒░▒▒░▀▒▒▒▒░▀░▒▒▒░▒
                  ▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓▒▓▓▒▒▒░▒▒░░  ░▒▒░  ░▒▒▒▒
                   ▀▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒░░▒░░    ░▒▒  ░ ▀▒▒
                     ▀▓▓█▓▓▓▓▓▓▓▓▓▓▒▒░░▒▒░░   ░░░▓░ ▓░░░▒
                       ▀▀█▓███▓▓▓▓▓▒▒░░░▒░░  ░█▓░█▓░█▓▓▄▒░
                          ░▓██▓▓▓▓▓▒▒░░░▒░░  ░████▓▒▓█▓▀░▀▄
                          ░▓██▓▓▓▓▓▒▒▒░░░▒░░  ▒██▓▒▒▒▒▒▒░░░▒
                           ████▓▓▓▓▓▒▒▒▒▒▒▒▒▒░░▒▓▓▒░░░░▒░░░▒░ ░░░░░
                           ░▓███▓▓▓▓▓▒▒░░░░░░░▒▒▒▒▒▒▒▒▒▒▒░░░ ░░░░░   ░
                             ▓███▓▓▓▓▓▒▓▒▒▒▒░░░░░░░░░▒▓▒▒░▀ ░░░  ░░░░░
                              ▀▒██▓▓▓▓▒▒▒▓▓▓▓▒▒▒▒▒▒▒▓▀▀░    ░░░░░░░░░     ░
                                 ▓▓▓▓▓▓▓▒▓▒▒▒▒▓▓▓▒▀░ ░░░░░▄░░░  ░░░  ░░░░░░
                                 ▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓     █▓▒░░▒░░░░ ░░░░░░░░
                                ▄▓▓▓▒▒▒▒▒░░░░░░░▒▄▄▄░▒▓▓▒▒░▀░
                               ░▓█▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒░░░▒  besiyata
                               ▓▓█▓▓▒▓▓▓▒▒▒░░░░░░▒▓▓▓▓▒▒▒▒▒░   dishmaya
                               ▓▓█▓▓▓▓▓▓▒▒▒░░░░░░░▒▓▓▒▀▀▀
                               ▓▓██▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▀
                                █▓▓█▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀
                               ▒▓▓▓▓▀░░▒▓▓▓▓▓▓▓▓▒▒░░▒
                              ▄▓▓▀░░░▄▓▓▓▓▒▒▒▒▒░░░░▄░
                             ▄███▄▄▓▓▓▓▓▓▓▒▒▒▒▒░░▒▒░
                           ▄▓▓▓█▓█▓▓███▓▓▓▓▓▓▓▓▓▓▓░
                       ▄░▓▓▓▓▓▓▀▒▓▓▓▒▒▓▒░░░▒▓▒░░░▓
               ▄▄▄░▒▓▓▓▓▓▓░▀▀   ▓▓▒░▓▒▒▒▒▒▒▒▒▒▒▄░░▀▀░░ ▄▄▄▄
     ▄▄▄▒▒▓▓█▓▓▓▓▓▀▀▀▀▀        ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▀░░▀░░▒▒▒░░░   ░░░░░
  ▄▓▓▓▒▀▀                      ▓▒▓▓▓▓▓▒▒▒▒▒▒▒▒▓░░░       ▒▒▒░░░░░░░░▒
  █▓▓▒      ▄▄▄                  ▀▓▒▓▒▒▒▓▓▓▓▓▓▒▒▒░░░░░░░░░▒▒░░░░░░░
   ▀▓▓▓▓▒▄▄▒▒▒▒▒▒▄▄                    ▀▀▀▀░░▒▒▒▒░░░░░░
       ▀▀▀▓▓▓▓▒▒▒▒▒▓▓▄▄
╔────────────────────────────────────────────────────────────────────────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § bell system five                          ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	the bourne executable & linkable format */

#if SupportsWindows() || SupportsMetal() || SupportsXnu()
apesh:	.ascii	"'\n#'\"\n"			# sixth edition shebang
	.ascii	"o=\"$(command -v \"$0\")\"\n"
#if SupportsXnu()
	.ascii	"if [ -d /Applications ]; then\n"
	.ascii	  "dd if=\"$o\""
	.ascii	    " of=\"$o\""
	.ascii	    " bs=8"
	.ascii	    " skip=\""
	.shstub	    ape_macho_dd_skip,2
	.ascii	    "\" count=\""
	.shstub	    ape_macho_dd_count,2
	.ascii	    "\" conv=notrunc 2>/dev/null\n"
	.ascii	"el"
#endif
	.ascii	"if exec 7<> \"$o\"; then\n"
	.ascii	  "printf '"
	.ascii	    "\\177ELF"			# 0x0: ⌂ELF
	.ascii	    "\\2"			#   4: long mode
	.ascii	    "\\1"			#   5: little endian
	.ascii	    "\\1"			#   6: elf v1.o
	.ascii	    "\\011"			#   7: FreeBSD
	.ascii	    "\\0"			#   8: os/abi ver.
	.ascii	    "\\0\\0\\0"			#   9: padding 3/7
	.ascii	    "\\0\\0\\0\\0"		#      padding 4/7
	.ascii	    "\\2\\0"			#  10: εxεcµταblε
	.ascii	    "\\076\\0"			#  12: NexGen32e
	.ascii	    "\\1\\0\\0\\0"		#  14: elf v1.o
	.shstub	    ape_elf_entry,8		#  18: e_entry
	.shstub	    ape_elf_phoff,8		#  20: e_phoff
	.shstub	    ape_elf_shoff,8		#  28: e_shoff
	.ascii	    "\\0\\0\\0\\0"		#  30: e_flags
	.ascii	    "\\100\\0"			#  34: e_ehsize
	.ascii	    "\\070\\0"			#  36: e_phentsize
	.shstub	    ape_elf_phnum,2		#  38: e_phnum
	.ascii	    "\\0\\0"			#  3a: e_shentsize
	.shstub	    ape_elf_shnum,2		#  3c: e_shnum
	.shstub	    ape_elf_shstrndx,2		#  3e: e_shstrndx
	.ascii	    "' >&7\n"
	.ascii	  "exec 7<&-\n"
	.ascii	"else\n"
	.ascii	  "exit 1\n"
	.ascii	"fi\n"
	.ascii	"exec \"$0\" \"$@\"\n"		# etxtbsy tail recursion
	.ascii	"R=$?\n"			# architecture optimistic
	.ascii	"\n"
	.ascii	"if [ $R -eq 126 ] && [ \"$(uname -m)\" != x86_64 ]; then\n"
	.ascii	  "if Q=\"$(command -v qemu-x86_64)\"; then\n"
	.ascii	    "exec \"$Q\" \"$0\" \"$@\"\n"
	.ascii	  "else\n"
	.ascii	    "echo error: need qemu-x86_64 >&2\n"
	.ascii	  "fi\n"
	.ascii	"elif [ $R -eq 127 ]; then\n"	# means argv[0] was wrong
	.ascii	"  exec \"$o\" \"$@\"\n"	# so do a path resolution
	.ascii	"fi\n"
	.ascii	"exit $R\n"
	.endobj	apesh
#endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */

#if SupportsSystemv() || SupportsMetal()
	.section .elf.phdrs,"a",@progbits
	.long	PT_LOAD
	.long	PF_R|PF_X
	.stub	ape_rom_offset,quad
	.stub	ape_rom_vaddr,quad
	.stub	ape_rom_paddr,quad
	.stub	ape_rom_filesz,quad
	.stub	ape_rom_memsz,quad
	.stub	ape_rom_align,quad
	.long	PT_LOAD
	.long	PF_R|PF_W
	.stub	ape_ram_offset,quad
	.stub	ape_ram_vaddr,quad
	.stub	ape_ram_paddr,quad
	.stub	ape_ram_filesz,quad
	.stub	ape_ram_memsz,quad
	.stub	ape_ram_align,quad
	.long	PT_GNU_STACK
	.long	PF_R|PF_W
	.stub	ape_stack_offset,quad
	.stub	ape_stack_vaddr,quad
	.stub	ape_stack_paddr,quad
	.stub	ape_stack_filesz,quad
	.stub	ape_stack_memsz,quad
	.stub	ape_stack_align,quad
#if SupportsOpenbsd() || SupportsNetbsd()
	.long	PT_NOTE
	.long	PF_R
	.stub	ape_note_offset,quad
	.stub	ape_note_vaddr,quad
	.stub	ape_note_paddr,quad
	.stub	ape_note_filesz,quad
	.stub	ape_note_memsz,quad
	.stub	ape_note_align,quad
#endif
	.previous
#endif /* SupportsSystemv() || SupportsMetal() */

#if SupportsOpenbsd()
	.section .note.openbsd.ident,"a",@progbits
openbsd.ident:
	.long	2f-1f
	.long	4f-3f
	.long	1
1:	.asciz	"OpenBSD"
2:	.align	4
3:	.long	0
4:	.size	openbsd.ident,.-openbsd.ident
	.type	openbsd.ident,@object
	.previous
#endif /* SupportsOpenbsd() */

#if SupportsNetbsd()
	.section .note.netbsd.ident,"a",@progbits
netbsd.ident:
	.long	2f-1f
	.long	4f-3f
	.long	1
1:	.asciz	"NetBSD"
2:	.align	4
3:	.long	901000000
4:	.size	netbsd.ident,.-netbsd.ident
	.type	netbsd.ident,@object
	.previous
#endif /* SupportsNetbsd() */

/*	                                      ▄▄███▄
	                                  ▄▄████████▄
	                               ▄█████████████▄
	                           ▄▄███▓▓▓▓▓▓▓▓▓▓▓███▄
	                       ▄▄█████▓▓▓█████████▓▓▓██▄
	                   ▄▄████████▓▓▓███████▓▓▓▓▓████▄
	                ▄█████░░░████▓▓█████▓▓▓▓█████████▄
	            ▄▄█████████░░░███▓▓█▓▓▓▓▒███████▓▓▒███▄
	         ▄██████████████░░░██▓▓▓▓███████████▓▓█████▄
	       ██████████████████░░░██▓▓▓█████████▓▓▓███████▄
	        ███░░░░░░█████████▓░░███▓▓▓▓▓▓▓▓▓▓▓█████▒▒▒██▄
	       █░███░░░██░░░░░░░░░██░░██████████████▒▒▒▒██████▄
	      ███████░░░█████████░░░░░░█████████▒▒▒▒▒██████████▄
	      █████ ██░░░███████████████████▒▒▒▒▒██░▒▒██████████▄
	      ██████ ██░░░██████████████░███▒████████▒▒██████████▄
	     ████████ ███░░█████████████░░████████████▒▒███████████
	     █████████ ███░░███████████░░██████████████▒▒███████████
	    ▄██████████ ██████████████ ░░███████████████▒▒███████████
	    ████████████ ███░░░░░█████░░█████████████████▒▒██████  █
	    █████████████ ██████░░░░░░░▒█████████████████████  ████▀
	     █████████████ ██████████░░░░░░░░░███████████  ████████
	      █████████████ ████████░░███████░░░██████ ▓██████████
	       █████████████ ██████░░░████████████  █████████████
╔────────────────────────────────────────────────────────────────────────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § nexstep carnegie melon mach object format ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	@note	hey xnu before we get upx'd email feedback jtunney@gmail.com
	@see	OS X ABI Mach-O File Format Reference, Apple Inc. 2009-02-04
	@see	System V Application Binary Interface NexGen32e Architecture
		Processor Supplement, Version 1.0, December 5th, 2018 */

#if SupportsXnu()
.section .macho,"a",@progbits
.align	__SIZEOF_POINTER__

ape_macho:
	.long	0xFEEDFACE+1
	.long	MAC_CPU_NEXGEN32E
	.long	MAC_CPU_NEXGEN32E_ALL
	.long	MAC_EXECUTE
	.long	5				# number of load commands
	.long	60f-10f				# size of all load commands
	.long	MAC_NOUNDEFS			# flags
	.long	0				# reserved
10:	.long	MAC_LC_SEGMENT_64
	.long	20f-10b				# unmaps first page dir
	.ascin	"__PAGEZERO",16			# consistent with linux
	.quad	0,0x200000,0,0			# which forbids mem <2m
	.long	0,0,0,0
20:	.long	MAC_LC_SEGMENT_64
	.long	30f-20b
	.ascin	"__TEXT",16
	.stub	ape_rom_vaddr,quad
	.stub	ape_rom_memsz,quad
	.stub	ape_rom_offset,quad
	.stub	ape_rom_filesz,quad
	.long	PROT_EXEC|PROT_READ|PROT_WRITE	# maxprot
	.long	PROT_EXEC|PROT_READ		# initprot
	.long	1				# segment section count
	.long	0				# flags
210:	.ascin	"__text",16			# section name (.text)
	.ascin	"__TEXT",16
	.stub	ape_text_vaddr,quad
	.stub	ape_text_memsz,quad
	.stub	ape_text_offset,long
	.long	12				# align 2**12 = 4096
	.long	0				# reloc table offset
	.long	0				# relocation count
	.long	MAC_S_ATTR_SOME_INSTRUCTIONS	# section type & attributes
	.long	0,0,0				# reserved
30:	.long	MAC_LC_SEGMENT_64
	.long	40f-30b
	.ascin	"__DATA",16
	.stub	ape_ram_vaddr,quad
	.stub	ape_ram_memsz,quad
	.stub	ape_ram_offset,quad
	.stub	ape_ram_filesz,quad
	.long	PROT_EXEC|PROT_READ|PROT_WRITE	# maxprot
	.long	PROT_READ|PROT_WRITE		# initprot
	.long	2				# segment section count
	.long	0				# flags
310:	.ascin	"__data",16			# section name (.data)
	.ascin	"__DATA",16
	.stub	ape_data_vaddr,quad
	.stub	ape_data_memsz,quad
	.stub	ape_data_offset,long
	.long	12				# align 2**12 = 4096
	.long	0				# reloc table offset
	.long	0				# relocation count
	.long	0				# section type & attributes
	.long	0,0,0				# reserved
320:	.ascin	"__bss",16			# section name (.bss)
	.ascin	"__DATA",16
	.stub	ape_bss_vaddr,quad		# virtual address
	.stub	ape_bss_memsz,quad		# memory size
	.long	0				# file offset
	.long	12				# align 2**12 = 4096
	.long	0				# reloc table offset
	.long	0				# relocation count
	.long	MAC_S_ZEROFILL			# section type & attributes
	.long	0,0,0				# reserved
40:	.long	MAC_LC_UUID
	.long	50f-40b
	.stub	ape_uuid1,quad
	.stub	ape_uuid2,quad
50:	.long	MAC_LC_UNIXTHREAD
	.long	60f-50b				# cmdsize
	.long	MAC_THREAD_NEXGEN32E		# flavaflav
	.long	(520f-510f)/4			# count
510:	.quad	0				# rax
	.quad	IMAGE_BASE_VIRTUAL		# rbx
	.quad	0				# rcx
	.quad	0				# rdx
	.quad	0				# rdi
	.quad	0				# rsi
	.quad	0				# rbp
	.quad	0				# rsp
	.quad	0				# r8
	.quad	0				# r9
	.quad	0				# r10
	.quad	0				# r11
	.quad	0				# r12
	.quad	0				# r13
	.quad	0				# r14
	.quad	0				# r15
	.quad	_xnu				# rip
	.quad	0				# rflags
	.quad	0				# cs
	.quad	0				# fs
	.quad	0				# gs
520:
60:

.endobj	ape_macho,globl,hidden
.previous /* .macho */
#endif /* SupportsXnu() */

/*                             ░░░░
                        ▒▒▒░░░▒▒▒▒▒▒▒▓▓▓░
                       ▒▒▒▒░░░▒▒▒▒▒▒▓▓▓▓▓▓░
                      ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓  ▒▓░
                      ▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓   ▓▓▓▓▓▓▒        ▒▒▒▓▓█
                     ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓  ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
                    ░▒▒▒░░░░▒▒▒▒▒▒▓▓▓▓▓▓   █▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
                    ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓░  ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
                   ▒▒▒▒░░░▒▒▒▒▒▒▒▓▓▓▓▓▓  ▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▒
                   ▒▒▒▒▓▓      ▓▒▒▓▓▓▓   ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
                                    ▒▓  ▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓
                   ░░░░░░░░░░░▒▒▒▒      ▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓█
                 ▒▒░░░░░░░░░░▒▒▒▒▒▓▓▓     ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓
                ░▒░░░░░░░░░░░▒▒▒▒▒▓▓   ▓░      ░▓███▓
                ▒▒░░░░░░░░░░▒▒▒▒▒▓▓░  ▒▓▓▓▒▒▒         ░▒▒▒▓   ████████████
               ▒▒░░░░░░░░░░░▒▒▒▒▒▓▓  ▒▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒░           ░███
               ▒░░░░░░░░░░░▒▒▒▒▒▓▓   ▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓            ███
              ▒▒░░░░░░░░░░▒▒▒▒▒▒▓▓  ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒            ▓██
              ▒░░░░░░░░░░░▒▒▒▒▒▓▓   ▓▓▓▓▒▒▒▒▒▒▒▒░░░▒▒▒▒▒▓           ▓██
             ▒▒░░░▒▒▒░░░▒▒░▒▒▒▓▓▒  ▒▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒           ███
                             ░▒▓  ░▓▓▓▓▒▒▒▒▒▒▒▒░░░░▒▒▒▒▓          ▓██
╔─────────────────────────────────────────────────────────────────▀▀▀────────│─╗
│ αcτµαlly pδrταblε εxεcµταblε § the new technology                        ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	The Portable Executable Format
	
	@see https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
	@see "The Portable Executable File Format from Top to Bottom",
	     Randy Kath, Microsoft Developer Network Technology Group. */

//	      ┌14:Uniprocessor Machine            ┌─────────────────────────┐
//	      │┌13:DLL                            │ PE File Characteristics │
//	      ││┌12:System                        ├─────────────────────────┤
//	      │││┌11:If Net Run From Swap         │ r │ reserved            │
//	      ││││┌10:If Removable Run From Swap  │ d │ deprecated          │
//	      │││││┌9:Debug Stripped              │ D │ deprecated with     │
//	      ││││││┌8:32bit Machine              │   │ extreme prejudice   │
//	      │││││││  ┌5:Large Address Aware     └───┴─────────────────────┘
//	      │││││││  │   ┌1:Executable
//	      │││││││  │   │┌0:Relocs Stripped
//	     d│││││││dr│Ddd││
PEEXE =  0b0000001000100011

//	     ┌15:TERMINAL_SERVER_AWARE            ┌─────────────────────────┐
//	     │┌14:GUARD_CF                        │ PE DLL Characteristics  │
//	     ││┌13:WDM_DRIVER                     ├─────────────────────────┤
//	     │││┌12:APPCONTAINER                  │ r │ reserved            │
//	     ││││┌11:NO_BIND                      └───┴─────────────────────┘
//	     │││││┌10:NO_SEH
//	     ││││││┌9:NO_ISOLATION
//	     │││││││┌8:NX_COMPAT
//	     ││││││││┌7:FORCE_INTEGRITY
//	     │││││││││┌6:DYNAMIC_BASE
//	     ││││││││││┌5:HIGH_ENTROPY_VA
//	     │││││││││││rrrrr
DLLSTD = 0b0000000100100000
DLLPIE = 0b0000000001100000
DLLEXE = DLLSTD

//	     ┌31:Writeable                        ┌─────────────────────────┐
//	     │┌30:Readable                        │ PE Section Flags        │
//	     ││┌29:Executable                     ├─────────────────────────┤
//	     │││┌28:Shareable                     │ o │ for object files    │
//	     ││││┌27:Unpageable                   │ r │ reserved            │
//	     │││││┌26:Uncacheable                 └───┴─────────────────────┘
//	     ││││││┌25:Discardable
//	     │││││││┌24:Contains Extended Relocations
//	     ││││││││        ┌15:Contains Global Pointer (GP) Relative Data
//	     ││││││││        │       ┌7:Contains Uninitialized Data
//	     ││││││││        │       │┌6:Contains Initialized Data
//	     ││││││││ o      │       ││┌5:Contains Code
//	     ││││││││┌┴─┐rrrr│  ooror│││rorrr
PETEXT = 0b01110000000000000000000001100000
PEDATA = 0b11000000000000000000000011000000
PEIMPS = 0b11000000000000000000000001000000

#if SupportsWindows() || SupportsMetal()

	.section .pe.header,"a",@progbits
	.align	__SIZEOF_POINTER__
ape_pe:	.ascin	"PE",4
	.short	kNtImageFileMachineNexgen32e
	.stub	ape_pe_shnum,short	# NumberOfSections
	.long	0x5c64126b		# TimeDateStamp
	.long	0			# PointerToSymbolTable
	.long	0			# NumberOfSymbols
	.stub	ape_pe_optsz,short	# SizeOfOptionalHeader
	.short	PEEXE			# Characteristics
	.short	kNtPe64bit		# Optional Header Magic
	.byte	14			# MajorLinkerVersion
	.byte	15			# MinorLinkerVersion
	.long	0			# SizeOfCode
	.long	0			# SizeOfInitializedData
	.long	0			# SizeOfUninitializedData
	.long	RVA(ape_pe_entry)	# EntryPoint
	.long	0			# BaseOfCode
	.quad	ape_pe_base		# ImageBase
	.long	4096			# SectionAlignment
	.long	4096			# FileAlignment
	.short	v_ntversion		# MajorOperatingSystemVersion
	.short	0			# MinorOperatingSystemVersion
	.short	0			# MajorImageVersion
	.short	0			# MinorImageVersion
	.short	v_ntsubversion		# MajorSubsystemVersion
	.short	0			# MinorSubsystemVersion
	.long	0			# Win32VersionValue
	.long	RVA(_end)		# SizeOfImage
	.long	RVA(_ehead)		# SizeOfHeaders
	.long	0			# Checksum
	.short	v_ntsubsystem		# Subsystem: 0=Neutral,2=GUI,3=Console
	.stub	v_ntdllchar,short	# DllCharacteristics
	.quad	0x0000000000100000	# StackReserve
	.quad	0x00000000000fc000	# StackCommit
	.quad	0			# HeapReserve
	.quad	0			# HeapCommit
	.long	0			# LoaderFlags
	.long	16			# NumberOfDirectoryEntries
	.long	0,0			# ExportsDirectory
	.stub	ape_idata,long		# ImportsDirectory
	.stub	ape_idata_idtsize,long	# ImportsDirectorySize
	.long	0,0			# ResourcesDirectory
	.long	0,0			# ExceptionsDirectory
	.long	0,0			# SecurityDirectory
	.long	0,0			# BaseRelocationTable
	.long	0,0			# DebugDirectory
	.long	0,0			# DescriptionString
	.long	0,0			# MachineSpecific
	.long	0,0			# ThreadLocalStorage
	.long	0,0			# LoadConfigurationDirectory
	.long	0,0			# BoundImportDirectory
	.stub	ape_idata,long		# ImportAddressDirectory
	.stub	ape_idata_iatsize,long	# ImportAddressDirectorySize
	.long	0,0			# DelayImportDescriptor
	.long	0,0			# ComPlusRuntimeHeader
	.long	0,0			# Reserved
	.endobj	ape_pe,globl
	.previous

	.section .pe.sections,"a",@progbits
	.ascin	".text",8		# Section Name
	.stub	ape_text_memsz,long	# Virtual Size or Physical Address
	.stub	ape_text_rva,long	# Relative Virtual Address
	.stub	ape_text_filesz,long	# Physical Size
	.stub	ape_text_offset,long	# Physical Offset
	.long	0			# Relocation Table Offset
	.long	0			# Line Number Table Offset
	.short	0			# Relocation Count
	.short	0			# Line Number Count
	.long	PETEXT			# Flags
	.previous

	.section .pe.sections,"a",@progbits
	.ascin	".data",8		# Section Name
	.stub	ape_ram_memsz,long	# Virtual Size or Physical Address
	.stub	ape_ram_rva,long	# Relative Virtual Address
	.stub	ape_ram_filesz,long	# Physical Size
	.stub	ape_ram_offset,long	# Physical Offset
	.long	0			# Relocation Table Offset
	.long	0			# Line Number Table Offset
	.short	0			# Relocation Count
	.short	0			# Line Number Count
	.long	PEDATA			# Flags
	.previous

#endif /* SupportsWindows() || SupportsMetal() */

	.section .idata.ro.idt.1,"a",@progbits
	.type	ape_idata_idtend,@object
	.type	ape_idata_idt,@object
	.globl	ape_idata_idt,ape_idata_idtend
	.hidden	ape_idata_idt,ape_idata_idtend
ape_idata_idt:
	.previous/*
	...
	decentralized content
	...
	*/.section .idata.ro.idt.3,"a",@progbits
	.long	0,0,0,0,0
ape_idata_idtend:
	.previous

	.section .piro.data.sort.iat.1,"aw",@progbits
	.type	ape_idata_iatend,@object
	.type	ape_idata_iat,@object
	.globl	ape_idata_iat,ape_idata_iatend
	.hidden	ape_idata_iat,ape_idata_iatend
ape_idata_iat:
	.previous/*
	...
	decentralized content
	...
	*/.section .piro.data.sort.iat.3,"aw",@progbits
ape_idata_iatend:
	.previous

#if SupportsMetal()
/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § early-stage read-only data                    │
╚──────────────────────────────────────────────────────────────────────────────╝
	better code/data separation (.head is rwx[real] rx[long]) */

//	NUL-Terminated Strings.
str.error:
	.asciz	"error: "
	.endobj	str.error
str.crlf:
	.asciz	"\r\n"
	.endobj	str.crlf
str.cpuid:
	.asciz	"cpuid"
	.endobj	str.cpuid
str.oldskool:
	.asciz	"oldskool"
	.endobj	str.oldskool
str.e820:
	.asciz	"e820"
	.endobj	str.e820
str.long:
	.asciz	"nolong"
	.endobj	str.long

//	Serial Line Configuration (8250 UART 16550)
//	If it's hacked, it'll at least get hacked very slowly.
sconf:	.short	1843200/*hz*/ / 16/*wut*/ / 9600/*baud*/
//
//	          ┌interrupt trigger level {1,4,8,14}
//	          │ ┌enable 64 byte fifo (UART 16750+)
//	          │ │ ┌select dma mode
//	          │ │ │┌clear transmit fifo
//	          │ │ ││┌clear receive fifo
//	          ├┐│ │││┌enable fifos
	.byte	0b00000000
//
//	          ┌dlab: flips configuration mode state
//	          │┌enable break signal
//	          ││ ┌parity {none,odd,even,high,low}
//	          ││ │ ┌extra stop bit
//	          ││ │ │┌data word length (bits+5)
//	          ││┌┴┐│├┐
	.byte	0b01000011
	.endobj	sconf,global,hidden

//	Global Descriptor Table
//
//	@note address portion only concern legacy modes
	.align	8
gdt:	.short	2f-1f		# table byte length
	.long	REAL(1f),0	# table address
	.zero	2
1:
//	          ┌G:granularity (1 → limit *= 0x1000)
//	          │┌D/B:default operation size (0 = 16|64bit, 1 = 32-bit)
//	          ││┌L:long mode
//	          │││┌AVL:this bit is thine (1<<52)
//	          ││││    ┌P:present
//	          ││││    │┌DPL:privilege
//	          ││││    ││ ┌─────────data/code(1)
//	          ││││    ││ │┌────data(0)──────code(1)
//	          ││││    ││ ││┌───conforming───expand-down
//	          ││││    ││ │││┌──writeable────readable
//	          ││││    ││ ││││┌─accessed─────accessed
//	          ││││    ││ │││││
//	          ││││ ┌──││─│││││───────────────────────────────┐
//	      ┌───││││─│──││─│││││───────────┐                   │
//	  ┌───┴──┐││││┌┴─┐│├┐│││││┌──────────┴───────────┐┌──────┴───────┐
//	  │      ││││││  ││││││││││          base address││ segment limit│
//	  │      ││││││  ││││││││││               32 bits││       20 bits│
//	  │      ││││││  ││││││││││                      ││              │
//	  6666555555555544444444443333333333222222222211111111110000000000
//	  3210987654321098765432109876543210987654321098765432109876543210
//	  │      ││││││  ││││││││││                      ││              │
.quad	0b0000000000000000000000000000000000000000000000000000000000000000 # 0
.quad	0b0000000000001111100110100000000000000000000000001111111111111111 # 8
.quad	0b0000000000001111100100100000000000000000000000001111111111111111 #16
.quad	0b0000000011001111100110100000000000000000000000001111111111111111 #24
.quad	0b0000000011001111100100100000000000000000000000001111111111111111 #32
.quad	0b0000000010101111100110110000000000000000000000001111111111111111 #40
.quad	0b0000000010101111100100110000000000000000000000001111111111111111 #48
2:	.endobj	gdt,global,hidden

/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § multiboot stub                                │
╚──────────────────────────────────────────────────────────────────────────────╝
	boot modernized for the nineties */

#define GRUB_MAGIC 0x1BADB002
#define GRUB_EAX 0x2BADB002
#define GRUB_AOUT (1 << 16)
#define GRUB_CHECKSUM(FLAGS) (-(GRUB_MAGIC + (FLAGS)) & 0xffffffff)

//	Grub Header.
	.align	4
ape_grub:
	.long	GRUB_MAGIC			# Magic
	.long	GRUB_AOUT			# Flags
	.long	GRUB_CHECKSUM(GRUB_AOUT)	# Checksum
	.long	RVA(ape_grub)			# HeaderPhysicalAddress
	.long	IMAGE_BASE_PHYSICAL		# TextPhysicalAddress
	.long	PHYSICAL(_edata)		# LoadEndPhysicalAddress
	.long	PHYSICAL(_end)			# BssEndPhysicalAddress
	.long	RVA(ape_grub_entry)		# EntryPhysicalAddress
	.endobj	ape_grub,globl

//	Grub Entrypoint.
//	Takes CPU out of legacy mode and jumps to normal entrypoint.
//	@noreturn
	.align	4
ape_grub_entry:
	.code32
//	cmp	$GRUB_EAX,%eax
//	jne	triplf
	push	$0
	popf
	mov	$0x40,%dl
	mov	%cr0,%eax
	and	$~CR0_PE,%eax
	mov	%eax,%cr0
	ljmpw	$0,$REAL(pc)
	.code16
	.endfn	ape_grub_entry

/*─────────────────────────────────────────────────────────────────────────────╗
│ αcτµαlly pδrταblε εxεcµταblε § real mode                                     │
╚──────────────────────────────────────────────────────────────────────────────╝
	the default mode of operation on modern cpus */

realmodeloader:
	call	rlinit
	call	sinit4
	.optfn	_start16
	call	_start16
	call	longmodeloader
	.endfn	realmodeloader

	.section .sort.text.real.init.1,"ax",@progbits
	.type	rlinit,@function
rlinit:	.previous/*
	...
	decentralized function
	...
	*/.section .sort.text.real.init.3,"ax",@progbits
	ret
	.previous

/*                                                               █ █▒
                                                               █     █
                                        █▓▄                   █       █
                                       ▒▓  ░█░         ░▒▓▓███░        █▒
                                       ▒▓      ▒▓███▓▒░                 ░▓
                                        █                                ▓░
                                      ▄██░                                █
                                     ▓▓    ▓██░              ▓█░▓█        ▒▓
                                    ▒█   ░█    █            ░▓    █        █
                                    █░    █   ░▓             ▀▒  █░        █
                                    █▒     ▀▒░                             ▓▓
                        ▄▄▄▓████▓▓▒░ █                 ▄▄▄▄▓▓▓█▓▓▓▓▒░     ▒█
                    ▄▓▓▀              ▒       ░█     ▄▓▀                ░███▒
                   ▓▀                  ░░      ▀▓▄▄▄▒▒                     █
                   █                     ░░█▒       ▒█        ▒▓           █
                   ▀█       ▄▄▄▄▄▄▄▄▄▄               ▀▀░▓██▓               █
                     ▀■▄▄▄■▀          ▀▀█▄                                 █
                                         ▀▀█▄                              █
                                            ▀█▄                            █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
                                              █▌                           █
╔──────────────────────────────────────────────────────────────────────────▀─│─╗
│ αcτµαlly pδrταblε εxεcµταblε § long mode loader                          ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│─╝
	long mode is long */

longmodeloader:
	call	lcheck
	call	a20
	call	e820
	call	pinit
	call	golong
	.endfn	longmodeloader

//	Long Mode Hardware Check
lcheck:	pushf				# check for i8086 / i8088 / i80186
	pop	%ax
	test	$0x80,%ah		# see intel manual volume 1 20.1.2
	jnz	9f			# we now assume 32bit is supported
	pushfl				# now check for i386 or early i486
	pop	%eax			# test ability to change cpuid bit
	mov	%eax,%ecx
	mov	$1<<21,%ebx
	xor	%ebx,%eax
	push	%eax
	popfl
	pushfl
	pop	%eax
	cmp	%eax,%ecx
	je	12f			# we assume cpuid inst is available
	or	%ebx,%eax		# puts cpuid bit in the on position
	push	%eax
	popfl
	mov	$0x80000000,%edi	# get amd ext cpuid thingy length
	mov	%edi,%eax
	inc	%edi
	cpuid				# clobbers eax, ebx, ecx, and edx
	cmp	%edi,%eax
	jl	10f
	mov	%edi,%eax
	cpuid
	mov	$1<<29,%edi		# need nexgen32e long mode support
	and	%edi,%edx
	cmp	%edi,%edx
	jne	10f
	xor	%ax,%ax
1:	ret
9:	mov	$REAL(str.oldskool),%di
	jmp	20f
10:	mov	$REAL(str.long),%di
	jmp	20f
12:	mov	$REAL(str.cpuid),%di
20:	call	rldie
	.endfn	lcheck

//	Gets memory map from BIOS.
e820:	mov	$0x0510>>4,%di		# mman::e820
	mov	%di,%es
	xor	%edi,%edi		# es:di is destination buffer
	xor	%ebx,%ebx		# ebx is an api state tracker
1:	mov	$0xE820,%eax		# magic
	mov	$8+8+4+4,%ecx		# sizeof(struct SmapEntry)
	mov	$0x534d4150,%edx	# magic number
	int	$0x15			# ax,bx,cx,dx,di → ax,bx,cx
	jc	9f			# cf = unsupported or abuse
	cmp	%edx,%eax		# more magic means success
	jne	9f
	test	%cx,%cx			# discard empty results
	jz	5f
	cmp	$8+8+4+1,%cx		# discard if ignore flag
	jb	4f
	testb	$1/*ignore*/,8+8+4/*SmapEntry::__acpi3*/(%di)
	jnz	5f
4:	add	$8+8+4+4,%di		# keep entry
5:	test	%ebx,%ebx		# last entry?
	jz	8f
	cmp	$0x1000,%di
	jb	1b
8:	ret
9:	mov	$REAL(str.e820),%di
	call	rldie
	.endfn	e820

//	Asks keyboard to grant system 65,519 more bytes of memory.
//
//	Yup.
//
//	@assume	realmode && df=0
//	@clob	ax,di,si,es,flags
//	@mode	real
//	@see	wiki.osdev.org/A20_Line
a20:	cli
	push	%ds
	xor	%ax,%ax
	mov	%ax,%es
	dec	%ax
	mov	%ax,%ds
	mov	$0x0500,%di
	mov	$0x0510,%si
	mov	%es:(%di),%al
	push	%ax
	mov	%ds:(%si),%al
	push	%ax
	movb	$0x00,%es:(%di)
	movb	$0xff,%ds:(%si)
	cmpb	$0xff,%es:(%di)
	pop	%ax
	mov	%al,%ds:(%si)
	pop	%ax
	mov	%al,%es:(%di)
	pop	%ds
	jne	3f
	mov	$1,%ax
	call	1f
	mov	$0xad,%al
	out	%al,$0x64
	call	1f
	mov	$0xd0,%al
	out	%al,$0x64
	call	2f
	in	$0x60,%al
	push	%ax
	call	1f
	mov	$0xd1,%al
	out	%al,$0x64
	call	1f
	pop	%ax
	or	$2,%al
	out	%al,$0x60
	call	1f
	mov	$0xae,%al
	out	%al,$0x64
	call	1f
	jmp	a20
1:	in	$0x64,%al
	test	$2,%al
	jnz	1b
	ret
2:	in	$0x64,%al
	test	$1,%al
	jz	2b
	ret
3:	sti
5:	ret
	.endfn	a20

//	Initializes long mode paging.
pinit:	push	%ds
#define	SEG 0x79000
	mov	$SEG>>4,%ax
	mov	%ax,%ds
	movl	$0x7d000+PAGE_V+PAGE_RW,0x7e000-SEG	# PDPT←PML4T (+)
	movl	$0x7c000+PAGE_V+PAGE_RW,0x7e800-SEG	# PDPT←PML4T (-)
	movl	$0x7b000+PAGE_V+PAGE_RW,0x7d000-SEG	# PDT←PDPT   (+)
	movl	$0x7a000+PAGE_V+PAGE_RW,0x7c000-SEG	# PDT←PDPT   (-)
	movl	$0x79000+PAGE_V+PAGE_RW,0x7b000-SEG	# PD←PDT     (+)
	movl	$0x79000+PAGE_V+PAGE_RW,0x7a000-SEG	# PD←PDT     (-)
	mov	$512,%cx				# PD±2MB
	mov	$PAGE_V+PAGE_RW,%eax
	xor	%si,%si
0:	mov	%eax,(%si)
	add	$0x1000,%eax
	add	$8,%si
	loop	0b
	mov	$0x7e000,%eax				# PML4T←CR3
	mov	%eax,%cr3
	pop	%ds
	ret
	.endfn	pinit

//	Switch from Real Mode → Long Mode
//
//	@see	Intel Manual V3A §4.1.2
golong:	cli
	lidt	0x1522					# mman::bad_idt
	mov	%cr4,%eax
	or	$CR4_PAE|CR4_PGE|CR4_OSFXSR,%eax
	mov	%eax,%cr4
	movl	$EFER,%ecx
	rdmsr
	or	$EFER_LME|EFER_SCE,%eax
	wrmsr
	lgdt	REAL(gdt)
	mov	%cr0,%eax
	or	$CR0_PE|CR0_PG|CR0_MP,%eax
	and	$~CR0_EM,%eax
	mov	%eax,%cr0
	ljmp	$GDT_LONG_CODE,$REAL(long)
	.endfn	golong

//	Long mode is long.
	.code64
long:	push	$GDT_LONG_DATA
	pop	%rax
	mov	%eax,%ds
	mov	%eax,%ss
	mov	%eax,%es
	mov	%eax,%fs
	mov	%eax,%gs
	mov	$0x80000,%esp
	xor	%r12d,%r12d
	xor	%r13d,%r13d
	xor	%r14d,%r14d
	xor	%r15d,%r15d
	xor	%ebx,%ebx
	xor	%ebp,%ebp
	push	%rbp
	mov	$0x0500,%rdi			# mman
	mov	%cr3,%rsi
	mov	$IMAGE_BASE_REAL,%edx
	call	__map_phdrs
	push	$0x037f
	fldcw	(%rsp)
	movabs	$1f,%rax
	jmp	*%rax
1:	movabs	$ape_stack_vaddr,%rsp
	add	$ape_stack_memsz,%rsp
#if USE_SYMBOL_HACK
	.byte	0x0f,0x1f,0207			# nop rdi binbase
	.long	(IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
#endif
	movl	$0,0x7b000			# unmap null 2mb
	.weak	__hostos
	ezlea	__hostos,ax
	test	%rax,%rax
	jz	1f
	movb	$METAL,(%rax)
1:	xor	%eax,%eax
	xor	%ecx,%ecx
	xor	%edx,%edx
	xor	%edi,%edi
	xor	%esi,%esi
	xor	%r8d,%r8d
	xor	%r9d,%r9d
	xor	%r10d,%r10d
	xor	%r11d,%r11d
	push	$0				# auxv[1][1]
	push	$0				# auxv[1][0]
	push	$.Larg0				# auxv[0][1]
	push	$31				# auxv[0][0] AT_EXECFN
	push	$0				# envp[1]
	push	$.Lenv0				# envp[0]
	push	$0				# argv[1]
	push	$.Larg0				# argv[0]
	push	$1				# argc
	jmp	_start
	.endfn	long

	.rodata
.Larg0:	.asciz	"ape.com"
.Lenv0:	.asciz	"METAL=1"
	.previous

#endif /* SupportsMetal() */

//	Avoid linker script variables appearing as code in objdump.
	.macro	.ldsvar	name:req
	.type	\name,@object
	.weak	\name
	.endm
	.ldsvar	_end
	.ldsvar	_etext
	.ldsvar	v_ape_realsectors
	.ldsvar	v_ape_highsectors
	.ldsvar	ape_idata_ro
	.ldsvar	ape_pad_rodata
	.ldsvar	ape_piro
	.ldsvar	ape_piro_end
	.type	ape_macho_end,@object
	.type	ape_note,@object
	.type	ape_note_end,@object
	.type	ape_note_vaddr,@object
	.type	ape_phdrs,@object
	.type	ape_pe_sections,@object
	.type	ape_pe_sections_end,@object
	.type	ape_text_nops,@object
	.type	__test_end,@object

	.section .commentprologue,"a",@progbits
	.type	kLegalNotices,@object
	.hidden	kLegalNotices
kLegalNotices:/*
	...
	decentralized content
	...
	*/.previous
	.section .commentepilogue,"a",@progbits
	.byte	0
	.previous

	.section .ape.pad.head,"a",@progbits
	.type	ape_pad_head,@object
	.hidden	ape_pad_head
ape_pad_head:
	.previous

	.section .ape.pad.text,"a",@progbits
	.type	ape_pad_text,@object
	.hidden	ape_pad_text
ape_pad_text:
	.previous

	.section .ape.pad.privileged,"a",@progbits
	.type	ape_pad_privileged,@object
	.hidden	ape_pad_privileged
ape_pad_privileged:
	.previous

	.section .ape.pad.rodata,"a",@progbits
	.type	ape_pad_rodata,@object
	.hidden	ape_pad_rodata
ape_pad_rodata:
	.previous

	.section .ape.pad.data,"a",@progbits
	.type	ape_pad_data,@object
	.hidden	ape_pad_data
ape_pad_data:
	.previous

	.section .idata.ro,"a",@progbits
	.type	ape_idata_ro,@object
	.hidden	ape_idata_ro
ape_idata_ro:
	.previous

	.section .dataprologue,"aw",@progbits
	.type	__data_start,@object
	.globl	__data_start
	.hidden	__data_start
__data_start:
	.previous

.end
